home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / cp14.zip / CP.C < prev    next >
C/C++ Source or Header  |  1992-03-20  |  13KB  |  526 lines

  1. /*
  2. [76703,4265]
  3. NUTTER.LST                01-Aug-88 29168
  4.  
  5.     Keywords: NUTTER AUG88 C SOURCE CONTROL
  6.  
  7.     Automatic Module Control in C - source listings from Stewart Nutters
  8.     article in the August 1988 issue of DDJ.
  9.  
  10. LISTING 1
  11. */
  12.  
  13. /* print a visual tree representation of a 'C' program */
  14. /* cp.c */
  15.  
  16. /***********************************************************
  17.  
  18.   cprinter - print a visual tree representation
  19.     of a 'C' program
  20.  
  21.   copyright 1987, Stewart A. Nutter
  22.  
  23.   Please do not distribute this for profit. For
  24.   individual use only.
  25.  
  26.   written by: Stewart A. Nutter
  27.  
  28.  **********************************************************/
  29.  
  30. #define MAINMODULE 1
  31. #include "cp.h"
  32.  
  33. /* v1.1 Prototypes */
  34. int xref(char *fname);
  35.  
  36. /* external in cpfuncts.c */
  37. extern int find_mod(char *buf);
  38. extern void getstats(void);
  39. extern int doprint(int n);
  40. extern void pagebreak(void);
  41. extern void leftmargin(void);        /* v1.1 */
  42. extern char getnext(FILE *stream);
  43. extern void pushc(char c);
  44. extern int strcheck(char c);
  45. extern int addlist(struct Func_list *p, char *buf, int cnt);
  46.  
  47.  
  48. void main(int argc, char **argv)    /* v1.1 made void */
  49.  
  50. {
  51.     char szName[20];            /* input file name */
  52.     int l, i;                    /* index variables */
  53.     int sflag;
  54.     int pcnt;
  55.     int tmp;
  56.     int pmax;                    /* max number of xref columns */
  57.     int index;
  58.     FILE *stream;
  59.     struct Pages *p;
  60.     long int total;                /* total number of bytes */
  61.     long int ltotal;            /* total number of lines */
  62.  
  63.     pFlist = Flist;
  64.     pMlist = Mlist;
  65.     pMnames = Mnames;
  66.  
  67.     for (i = 0; i < 50; i++)        /* clear out the recursion list */
  68.         rlist[i] = NULL;
  69.  
  70. /* v1.4 Funny sort of bug:  during the initial processing,
  71.  * the first string in our string segment gets printed!
  72.  */
  73.     printf("\ncp - ver. 1.3, (C) 1987, 1988  Stewart A. Nutter");
  74.     printf("\n     written by Stewart A. Nutter\n");
  75.  
  76. /* no arguments - print instructions */
  77.  
  78.     if (argc < 2) {
  79.         printf("\ncp listfile [ outfile ] [ /l:xx /w:yy /t:main /s:z ]\n");
  80.         printf("     outfile            = \"prn\" \n");
  81.         printf("     l: page length     = 66       [0, 50-255]\n");
  82.         printf("     w: page width      = 80       [80-255]\n");
  83.         printf("     m: left margin     = 8        [0-30]\n");
  84.         printf("     r: right margin    = 8        [0-30]\n");
  85.         printf("     t: target function = \"main\"\n");
  86.         printf("     s: statistics only = 0        [0=all, 1=stats only]\n");
  87.         printf("\n");
  88.         printf("Notes: 1. Maximum recursive function displacement of 50.\n");
  89.         printf("       2. Maximum number of functions calls is %d.\n", MAXFNCTS);
  90.         printf("       3. Maximum number of modules is %d.\n", MAXMODULES);
  91.         exit(0);
  92.     }
  93.     if ((stream = fopen(argv[1], "r")) == NULL) {
  94.         fprintf(stderr, "\n%s", strerror(errno));
  95.         exit(1);
  96.     }
  97. /* an output file name was given? */
  98.  
  99.     index = 2;
  100.  
  101. #ifdef NO_STDOUT
  102.     if (argc > 2 && argv[index][0] != '/') {
  103.         output = fopen(argv[2], "w+");
  104.         index++;
  105.     } else
  106.         output = fopen("prn", "w+");        /* prn device by default */
  107. #endif
  108.  
  109.     for (i = index; i < argc; i++) {
  110.         if ((argv[i][0] == '/')
  111.          && (strlen(argv[i]) > 3)
  112.          && (argv[i][2] == ':')) {
  113.             switch (argv[i][1]) {
  114.             case 'l':                /* change the page length */
  115.                 tmp = atoi(&argv[i][3]);
  116.                 if (((tmp > 50) && (tmp < 256)) || (tmp == 0))
  117.                     pl = tmp;
  118.                 break;
  119.  
  120.             case 'm':                /* change the left margin */
  121.                 tmp = atoi(&argv[i][3]);
  122.                 if ((tmp >= 0) && (tmp <= 30))
  123.                     lm = tmp;
  124.                 break;
  125.  
  126.             case 'r':                /* change the right margin */
  127.                 tmp = atoi(&argv[i][3]);
  128.                 if ((tmp >= 0) && (tmp <= 30))
  129.                     rm = tmp;
  130.                 break;
  131.  
  132.             case 's':                /* set the stats only? */
  133.                 stats = atoi(&argv[i][3]);
  134.                 break;
  135.  
  136.             case 't':                /* change the target function */
  137.                 strcpy(target, &argv[i][3]);
  138.                 break;
  139.  
  140.             case 'w':                /* change the width */
  141.                 tmp = atoi(&argv[i][3]);
  142.                 if ((tmp > 79) && (tmp < 256))
  143.                     pw = tmp;
  144.                 break;
  145.  
  146.             }
  147.         } else {
  148.             printf("\nUnknown argument: %s", argv[i]);
  149.             exit(1);
  150.         }
  151.     }
  152.  
  153. #ifdef NO_STDOUT
  154.     if (output == NULL) {
  155.         fprintf(stderr, "\n%s", strerror(errno));
  156.         exit(1);
  157.     }
  158. #endif
  159.  
  160.     width = pw - lm - rm;
  161.     if (width < 40) {
  162.         fprintf(stderr, "\nThe page width is too narrow.");
  163.         exit(1);
  164.     }
  165.     printf("\n");
  166.  
  167.  
  168. /* read the input file for file names */
  169.  
  170.     while (!feof(stream)) {
  171.         szName[0] = '\0';
  172.         fgets(szName, 19, stream);
  173.         if ((l = strlen(szName)) > 1) {
  174.             if (szName[l - 1] == '\n')
  175.                 szName[l - 1] = '\0';        /* remove newline char */
  176.             xref(szName);
  177.         }
  178.     }
  179.  
  180. /* pointer list for sort */
  181.  
  182.     for (i = 0, pMlist = Mlist; i < Mqty; i++) {
  183.         pm[i] = pMlist++;
  184.     }
  185.  
  186.     printf("\n\nSorting the function list...\n");
  187.  
  188.     sflag = 1;
  189.     while (sflag) {                /* sort the function names */
  190.         sflag = 0;
  191.         for (i = 0; i < Mqty - 1; i++) {
  192.             if (strcmp(pm[i]->function, pm[i + 1]->function) > 0) {
  193.                 sflag = 1;
  194.                 pMlist = pm[i];
  195.                 pm[i] = pm[i + 1];
  196.                 pm[i + 1] = pMlist;
  197.             }
  198.         }
  199.     }
  200.     i = find_mod(target);        /* must start with the target function */
  201.  
  202.     if (i >= 0) {                /* 'main' must exist */
  203.         depth = 0;
  204.  
  205.         printf("Checking for usage...\n");
  206.  
  207. /* check how many times each function is used */
  208.  
  209.         getstats();
  210.         depth = 0;
  211.         bfr[0] = 0;
  212.  
  213.         printf("Starting the printout...\n");
  214.  
  215.         line = 0;
  216.         if (stats == 0) {
  217.             pm[i]->used = 1;        /* set so main shows up in the list */
  218.             doprint(i);                /* print the non-library functions */
  219.  
  220.             for (i = 0; i < Mqty; i++) {        /* print defined functions now */
  221.                 printf("\n");        /* v1.4 */
  222.                 line++;
  223.                 if (pm[i]->used > 1) {        /* must be used more than once */
  224.                     doprint(i);        /* print the tree structure */
  225.                 }
  226.             }
  227.         }
  228. /* print statistics on the modules */
  229.  
  230.         line = 9999;                /* force a new page */
  231.         pMnames = Mnames;
  232.         pagebreak();
  233.         leftmargin();
  234.         printf("Module statistics :\n");    /* v1.4 */
  235.         line++;
  236.         total = 0L;
  237.         ltotal = 0L;
  238.         for (i = 0; i < Mcnt; i++) {        /* print module names & sizes */
  239.             pagebreak();
  240.             leftmargin();
  241.             printf("%-12s - %5u lines, %6ld bytes\n",        /* v1.4 */
  242.                     pMnames->name, pMnames->length,
  243.                     pMnames->size);
  244.             total += pMnames->size;
  245.             ltotal += pMnames->length;
  246.             line++;
  247.             pMnames++;
  248.         }
  249.         fputc('\n',stdout);     /* v1.4 */
  250.         leftmargin();
  251.         printf(                /* v1.4 */
  252.            "Total source size = %ld bytes in %ld lines for %d modules\n",
  253.                 total, ltotal, Mcnt);
  254.  
  255. /* print the used function page index */
  256.  
  257.         line = 9999;                /* force a new page */
  258.         pagebreak();
  259.         leftmargin();
  260.         printf("Function index :\n");    /* v1.4 */
  261.         line++;
  262.         for (i = 0; i < Mqty; i++) {        /* print used function names */
  263.             pMlist = pm[i];
  264.             if (pMlist->used > 0) {
  265.                 pagebreak();
  266.                 leftmargin();
  267.                 printf(                    /* v1.4 */
  268.                         "%-25s - %-12s - used =%d \n",
  269.                         pMlist->function, (pMlist->name)->name,
  270.                         pMlist->used);
  271.                 line++;
  272.             }
  273.         }
  274.  
  275. /* print the function page cross reference */
  276.  
  277.         if (stats == 0 && pl > 0) {        /* print everything */
  278.             pmax = (int) (width - 27) / 5;
  279.             line = 9999;        /* force a new page */
  280.             pagebreak();
  281.             leftmargin();
  282.             printf("Function cross reference :\n");    /* v1.4 */
  283.             line++;
  284.             for (i = 0; i < Mqty; i++) {        /* print used function names */
  285.                 pMlist = pm[i];
  286.                 if (pMlist->used > 0) {
  287.                     pagebreak();
  288.                     leftmargin();
  289.                     printf("%-25s- ", pMlist->function);    /* v1.4 */
  290.                     p = pMlist->pg;
  291.                     if (p != NULL) {
  292.                         pcnt = 0;
  293.                         while (p->next != NULL) {
  294.                             printf("%4d,", p->pg);    /* v1.4 */
  295.                             p = p->next;
  296.                             pcnt++;
  297.                             if (pcnt >= pmax) {
  298.                                 fputc('\n', stdout);
  299.                                 leftmargin();
  300.                                 printf("%27s", " ");    /* v1.4 */
  301.                                 line++;
  302.                                 pcnt = 0;
  303.                             }
  304.                         }
  305.                         printf("%4d\n", p->pg);    /* v1.4 */
  306.                         line++;
  307.                     } else
  308.                         printf("\n");    /* v1.4 */
  309.                 }
  310.             }
  311.         }
  312. /* print statistics on all unused modules */
  313.  
  314.         line = 9999;                /* force a new page */
  315.         pagebreak();
  316.         leftmargin();
  317.         printf("Un-used function list :\n");    /* v1.4 */
  318.         line++;
  319.         pcnt = 0;
  320.         for (i = 0; i < Mqty; i++) {        /* print unused function names */
  321.             pMlist = pm[i];
  322.             if (pMlist->used == 0) {
  323.                 pagebreak();
  324.                 pcnt++;
  325.                 leftmargin();
  326.                 printf(            /* v1.4 */
  327.                         "%-25s - %-12s \n",
  328.                         pMlist->function, (pMlist->name)->name);
  329.                 line++;
  330.             }
  331.         }
  332.         if (pcnt == 0) {
  333.             leftmargin();
  334.             printf(            /* v1.4 */
  335.                     "No un-used functions in the list.\n");
  336.         }
  337. /* print module comments */
  338.  
  339.         line = 9999;                /* force a new page */
  340.         pMnames = Mnames;
  341.         pagebreak();
  342.         leftmargin();
  343.         printf("Module comments :\n");    /* v 1.4 */
  344.         line++;
  345.         for (i = 0; i < Mcnt; i++) {        /* print module names & comments */
  346.             pagebreak();
  347.             leftmargin();
  348.             printf(            /* v1.4 */
  349.                     "%12s -%s\n",
  350.                     pMnames->name, pMnames->cmt);
  351.             line++;
  352.             pMnames++;
  353.         }
  354.         printf("%c", 0x0c);        /* ending formfeed v1.4 */
  355.     }
  356. }
  357.  
  358.  
  359.  
  360. /* process the file for function names */
  361.  
  362. int xref(char *fname)
  363. {
  364.     int done;                        /* loop termination flag */
  365.     int brace_cnt;                /* count of the open braces */
  366.     int open_paren;                /* open paranthisis count */
  367.     int ret;                        /* return value */
  368.     int indx;                        /* for/next index */
  369.     int dflg;                        /* function definition flag */
  370.     static int wflg = 0;
  371.     char c;                        /* character read from disk file */
  372.     char buffer[50];                /* temporary buffer */
  373.     char bufr[256];                /* temporary buffer */
  374.     register char *p;                /* fast character pointer */
  375.     FILE *stream;                /* module file pointer */
  376.     struct Mod_list *cptr;        /* pointer to the module list structure */
  377.     static char back[] =
  378.     {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
  379.     8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8};
  380.  
  381.     printf("%cProcessing file: %-12s   ", 0x0d, fname);
  382.  
  383.     if ((stream = fopen(fname, "r")) == NULL)
  384.         return (-1);
  385.  
  386.     pp = pc;
  387.     if ((pMnames->name = strdup(fname)) == NULL) {
  388.         fprintf(stderr, "Ran out of memory.\n");
  389.         exit(1);
  390.     }
  391.     pMnames->length = 0;
  392.     pMnames->size = 0L;
  393.  
  394.     buffer[0] = 0;
  395.     p = buffer;
  396.  
  397.     open_paren = 0;
  398.     brace_cnt = 0;
  399.     firstcmt = 0;
  400.     filecmt[0] = 0;
  401.     done = 0;
  402.     ret = 0;
  403.     while (!ret) {
  404.         c = getnext(stream);
  405.         switch (c) {
  406.         case '{':
  407.             brace_cnt++;        /* increment the open brace count */
  408.             break;
  409.         case '}':
  410.             brace_cnt--;        /* decrement the open brace count */
  411.             break;
  412.         case '(':
  413.             if (open_paren == 0) {        /* first open paren only */
  414.                 open_paren = 1;
  415.             }
  416.             wflg = 1;
  417.             break;
  418.         case ' ':                /* skip tabs and spaces */
  419.         case '\t':
  420.             do {
  421.                 c = getnext(stream);
  422.             }
  423.             while (c == '\t' || c == ' ');
  424.             if (c != '(')
  425.                 wflg = 1;
  426.             pushc(c);
  427.             break;
  428.         case 0x1a:                /* end of the file indicator */
  429.             ret = 1;
  430.             wflg = 1;
  431.         default:
  432.  
  433. /* the character must be a variable character */
  434.  
  435.             if (strcheck(c)) {
  436.                 *p++ = c;
  437.                 *p = 0;
  438.             } else
  439.                 wflg = 1;
  440.             break;
  441.         }
  442.         if (wflg) {
  443.             if (buffer[0] && (buffer[0] < '0' || buffer[0] > '9')) {
  444.                 done = 1;
  445.             } else {
  446.                 p = buffer;
  447.                 buffer[0] = 0;
  448.                 open_paren = 0;
  449.             }
  450.             wflg = 0;
  451.         }
  452. /* if done != 0 there is a token */
  453.  
  454.         if (done) {
  455.             done = 0;
  456.             *p = 0;
  457.  
  458.             if (open_paren) {        /* functions start with an open paren */
  459.                 open_paren = 0;
  460.                 if (brace_cnt == 0) {        /* and no braces */
  461.                     dflg = 0;
  462.                     for (indx = 0; indx < 256 && dflg == 0; indx++) {
  463.                         c = getnext(stream);
  464.                         if (c == ';')
  465.                             dflg = 1;
  466.                         else if (c == '\n')
  467.                             dflg = 2;
  468.                         bufr[indx] = c;
  469.                     }
  470.                     if (dflg == 0) {
  471.                         fprintf(stderr, "\nSyntax error: ");
  472.                         fprintf(stderr, "Module description.\n");
  473.                         bufr[indx] = 0;
  474.                         fprintf(stderr, "\n%s\n", bufr);
  475.                         exit(1);
  476.                     }
  477. /* put the characters back to be read */
  478.  
  479.                     while (indx) {
  480.                         pushc(bufr[indx - 1]);
  481.                         indx--;
  482.                     }
  483.  
  484. /* this is a function definition */
  485.  
  486.                     if (dflg == 2) {
  487.                         printf("%-40s%s", buffer, back);
  488.                         pMlist->name = pMnames;
  489.                         pMlist->qty = 0;
  490.                         pMlist->ptr = pFlist;
  491.  
  492.                         /* allocate memory for name */
  493.  
  494.                         if ((pMlist->function = strdup(buffer))
  495.                             == NULL) {
  496.                             fprintf(stderr, "\nRan out of memory.");
  497.                             exit(1);
  498.                         }
  499.                         pMlist->used = 0;
  500.                         pMlist->pg = NULL;
  501.                         cptr = pMlist;
  502.                         pMlist++;
  503.                         Mqty++;
  504.                         if (Mqty > MAXMODULES) {
  505.                             fprintf(stderr,
  506.                                     "Too many new functions\n");
  507.                             exit(1);
  508.                         }
  509.                     }
  510.                 } else {
  511.                     cptr->qty += addlist(cptr->ptr,
  512.                                          buffer, cptr->qty);
  513.  
  514.                 }
  515.             }
  516.             p = buffer;
  517.             *p = 0;
  518.         }
  519.     }
  520.     fclose(stream);
  521.     pMnames->cmt = strdup(filecmt);
  522.     pMnames++;                        /* point to the next function data structure */
  523.     Mcnt++;                        /* count of the different functions */
  524.     return (ret);
  525. }
  526.